package com.yanqu.road;

import com.yanqu.road.ak13.YanQuWSSInit;
import com.yanqu.road.hs7.YanQuWSSSslInit;
import com.yanqu.road.netty.server.NettyParamOperator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.AttributeKey;

public final class AgentServerNettyService {

	private static Logger logger = LogManager.getLogger(AgentServerNettyService.class.getName());

	public static AttributeKey<Long> KEY_FOR_PLAYER_ID = AttributeKey.valueOf("CLIENT_KEY");
	public static AttributeKey<String> KEY_FOR_PLAYER_IP = AttributeKey.valueOf("IP");
	public static AttributeKey<String> KEY_FOR_SEC_WEBSOCKET_PROTOCOL = AttributeKey.valueOf("SEC-WEBSOCKET-PROTOCOL");

	private int port;
	private long serverId;
	private boolean isPortOpen = true;
	private ChannelFuture channelFuture;

	public AgentServerNettyService(long serverId, int port) {
		this.serverId = serverId;
		this.port = port;
	}

	public void start(boolean isSsl) throws Exception {
		boolean ePool = Epoll.isAvailable();
		int cpuNum = Runtime.getRuntime().availableProcessors();

		EventLoopGroup bossEventLoopGroup;
		EventLoopGroup workerEventLoopGroup;
		if (ePool) {
			bossEventLoopGroup = new EpollEventLoopGroup(cpuNum);
			workerEventLoopGroup = new EpollEventLoopGroup(cpuNum * 2 + 1);
		} else {
			bossEventLoopGroup = new NioEventLoopGroup(cpuNum);
			workerEventLoopGroup = new NioEventLoopGroup(cpuNum * 2 + 1);
		}

		try {
			channelFuture = getServerBootstrap(isSsl, ePool, bossEventLoopGroup, workerEventLoopGroup).bind(port).sync();
			channelFuture.channel().closeFuture().sync();
			logger.info("服务器:" + serverId + ",端口:" + port + ", 是否ePool:" + ePool);
		} finally {
			workerEventLoopGroup.shutdownGracefully();
			bossEventLoopGroup.shutdownGracefully();
			isPortOpen = false;
			logger.info("启动端口: " + port);
		}
	}

	private ServerBootstrap getServerBootstrap(boolean isSsl, boolean isEpoll, EventLoopGroup bossGroup, EventLoopGroup workerGroup) {
		ServerBootstrap bootstrap = new ServerBootstrap();
		bootstrap.group(bossGroup, workerGroup);
		bootstrap.channel(isEpoll ? EpollServerSocketChannel.class : NioServerSocketChannel.class);
		if (isSsl) {
			bootstrap.childHandler(new YanQuWSSSslInit());
		}else {
			bootstrap.childHandler(new YanQuWSSInit());
		}
		NettyParamOperator.buildSslWebsocketBootstrapOptions(bootstrap);
		return bootstrap;
	}

	public boolean isPortOpen() {
		return isPortOpen;
	}

	public void stop() {
		try {
			channelFuture.channel().close().sync();
		} catch (Exception e) {
			logger.error("netty server close fail.", e);
		}
	}

}
